#pragma once
#include "mkvmuxpin.hpp"

namespace MkvMux
{

class MkvStream;

class Inpin : public Pin, public IMemInputPin
{
    Inpin(const Inpin&);
    Inpin& operator=(const Inpin&);
    
protected:
    
    Inpin(Filter*, const wchar_t*);
    ~Inpin();
    
public:

    void Init();
    void Final();
    void Run();

    //IUnknown interface:
    
    HRESULT STDMETHODCALLTYPE QueryInterface(const IID&, void**);
    ULONG STDMETHODCALLTYPE AddRef();
    ULONG STDMETHODCALLTYPE Release();
    
    //IPin interface:

    HRESULT STDMETHODCALLTYPE Connect(IPin*, const AM_MEDIA_TYPE*);

    //HRESULT STDMETHODCALLTYPE Disconnect();

    HRESULT STDMETHODCALLTYPE ReceiveConnection( 
        IPin*,
        const AM_MEDIA_TYPE*);
        
    HRESULT STDMETHODCALLTYPE QueryInternalConnections( 
        IPin**,
        ULONG*);
        
    HRESULT STDMETHODCALLTYPE EndOfStream();

    HRESULT STDMETHODCALLTYPE BeginFlush();    

    HRESULT STDMETHODCALLTYPE EndFlush();
    
    HRESULT STDMETHODCALLTYPE NewSegment( 
        REFERENCE_TIME,
        REFERENCE_TIME,
        double);
        
    //IMemInputPin
    
    HRESULT STDMETHODCALLTYPE GetAllocator(
        IMemAllocator**);
    
    HRESULT STDMETHODCALLTYPE NotifyAllocator( 
        IMemAllocator*,
        BOOL);
    
    //HRESULT STDMETHODCALLTYPE GetAllocatorRequirements( 
    //    ALLOCATOR_PROPERTIES*);

    HRESULT STDMETHODCALLTYPE Receive(IMediaSample*);    
    
    HRESULT STDMETHODCALLTYPE ReceiveMultiple( 
        IMediaSample**,
        long,
        long*);
    
    HRESULT STDMETHODCALLTYPE ReceiveCanBlock();

    HANDLE m_hSample;

protected:

    class Lock
    {
        Lock(const Lock&);
        Lock& operator=(const Lock&);

    public:
        explicit Lock(Inpin*);
        ~Lock();
        
        void Seize(Inpin*);
        void Release();
        
    private:
        Filter* m_pFilter;
        
    };
        
   virtual HRESULT OnReceiveConnection(IPin*, const AM_MEDIA_TYPE&);
   //virtual HRESULT OnReceive(IMediaSample*);
   //virtual HRESULT OnReceive(IMediaSample*, Lock&) = 0;
   virtual HRESULT OnEndOfStream();
   //virtual HRESULT OnReceiveMultiple(
   //                 IMediaSample* const*, 
   //                 long, 
   //                 long&,
   //                 Lock&);
    
private:

   bool m_bEndOfStream;
   bool m_bFlush;
    
protected:

    MkvStream* m_pStream;
    virtual HRESULT OnInit() = 0;
    virtual void OnFinal() = 0;
   
    HRESULT Wait(Lock&);   
    virtual HANDLE GetOtherHandle() const = 0;
   
    HANDLE m_hStateChangeOrFlush;

};
    
}  //end namespace MkvMux

